<template>
  <!-- 按钮区域 -->
  <div class="j-super-query-button">
    <a-tooltip v-if="superQueryFlag" :mouseLeaveDelay="0.2">
      <template #title>
        <span>已有高级查询条件生效</span>
        <divider type="vertical" style="background-color: #fff" />
        <a @click="handleReset">清空</a>
      </template>
      <a-button-group>
        <a-button type="primary" @click="handleOpen">
          <AppstoreTwoTone :spin="true" />
          <span>高级查询</span>
        </a-button>
      </a-button-group>
    </a-tooltip>
    <a-button v-else type="primary" preIcon="ant-design:filter-outlined" @click="handleOpen">高级查询</a-button>
  </div>

  <!-- 高级查询弹框 -->
  <teleport to="body">
    <BasicModal title="高级查询构造器" :canFullscreen="false" :width="700" @register="registerFormModal" @ok="handleSubmit">
      <template #footer>
        <div style="float: left">
          <a-button :loading="loading" @click="handleReset">重置</a-button>
          <a-button :loading="loading" @click="handleSave">保存查询条件</a-button>
        </div>

        <a-button key="submit" type="primary" @click="handleSubmit">确定</a-button>
        <a-button key="back" @click="handleCancel">关闭</a-button>
      </template>

      <a-empty v-if="dynamicRowValues.values.length == 0">
        <div slot="description">
          <span>没有任何查询条件</span>
          <a-divider type="vertical" />
          <a @click="addOne(-1)">点击新增</a>
        </div>
      </a-empty>

      <a-row :class="'j-super-query-modal-content'">
        <a-col :sm="24" :md="24">
          <a-row v-show="dynamicRowValues.values.length > 0">
            <a-col :md="12" :xs="24">
              <a-form-item label="匹配模式" :labelCol="{ md: 6, xs: 24 }" :wrapperCol="{ md: 18, xs: 24 }" style="width: 100%">
                <a-select v-model="matchType" :getPopupContainer="(node) => node?.parentNode" style="width: 100%">
                  <a-select-option value="and">AND（所有条件匹配）</a-select-option>
                  <a-select-option value="or">OR（任意一个匹配）</a-select-option>
                </a-select>
              </a-form-item>
            </a-col>
          </a-row>

          <a-form
            v-show="dynamicRowValues.values.length > 0"
            ref="formRef"
            :class="'jee-super-query-form'"
            :model="dynamicRowValues"
            @finish="onFinish"
          >
            <a-space v-for="(item, index) in dynamicRowValues.values" :key="item.key" style="display: flex; margin-bottom: 8px" align="baseline">
              <a-form-item :name="['values', index, 'field']" style="width: 150px">
                <a-tree-select
                  style="width: 100%"
                  placeholder="请选择字段"
                  v-model:value="item.field"
                  show-search
                  tree-node-filter-prop="title"
                  allow-clear
                  tree-default-expand-all
                  :dropdown-style="{ maxHeight: '180px', overflow: 'auto' }"
                  @change="handleChangeField(item)"
                  :tree-data="fieldTreeData"
                />
              </a-form-item>
              <a-form-item :name="['values', index, 'rule']" style="width: 100px">
                <a-select style="width: 100%" placeholder="请选择匹配规则" :value="item.rule">
                  <a-select-option value="eq">等于</a-select-option>
                  <a-select-option value="like">包含</a-select-option>
                  <a-select-option value="right_like">以..开始</a-select-option>
                  <a-select-option value="left_like">以..结尾</a-select-option>
                  <a-select-option value="in">在...中</a-select-option>
                  <a-select-option value="ne">不等于</a-select-option>
                  <a-select-option value="gt">大于</a-select-option>
                  <a-select-option value="ge">大于等于</a-select-option>
                  <a-select-option value="lt">小于</a-select-option>
                  <a-select-option value="le">小于等于</a-select-option>
                </a-select>
              </a-form-item>
              <a-form-item :name="['values', index, 'val']" style="width: 180px">
                <online-super-query-val-component
                  style="width: 100%"
                  :schema="getSchema(item, index)"
                  :formModel="item"
                  :setFormModel="
                    (key, value) => {
                      setFormModel(key, value, item);
                    }
                  "
                  @submit="handleSubmit"
                />
              </a-form-item>

              <a-form-item>
                <a-button @click="addOne(index)" style="margin-right: 6px">
                  <PlusOutlined />
                </a-button>
                <a-button @click="removeOne(item)">
                  <MinusCircleOutlined />
                </a-button>
              </a-form-item>
            </a-space>
          </a-form>
        </a-col>
      </a-row>
      <!-- 查询记录 -->
      <a-card :class="historyCollapsed ? 'j-super-query-history-card collapsed' : 'j-super-query-history-card'" :bordered="false">
        <template #title><div>保存的查询</div></template>
        <a-empty v-if="saveTreeData.length === 0" class="j-super-query-history-empty" :image="simpleImage" description="没有保存的查询" />
        <a-tree v-else class="j-super-query-history-tree" :treeData="saveTreeData" :selectedKeys="[]" :show-icon="true" @select="handleTreeSelect">
          <template #title="{ title }">
            <div>
              <span :title="title">{{ title.length > 10 ? title.substring(0, 10) + '...' : title }}</span>
              <span class="icon-cancle"><close-circle-outlined @click="handleRemoveSaveInfo(title)" /></span>
            </div>
          </template>
          <template #custom>
            <file-text-outlined />
          </template>
        </a-tree>
        <div class="collapse-box" @click="historyCollapsed = !historyCollapsed">
          <Icon v-if="historyCollapsed" icon="ant-design:caret-left" />
          <Icon v-else icon="ant-design:caret-right" />
        </div>
      </a-card>
    </BasicModal>
  </teleport>

  <!-- 保存信息弹框 -->
  <a-modal title="请输入保存的名称" :open="saveInfo.visible" @cancel="saveInfo.visible = false" @ok="doSaveQueryInfo">
    <div style="height: 80px; line-height: 75px; width: 100%; text-align: center">
      <a-input v-model:value="saveInfo.title" style="width: 90%" placeholder="请输入保存的名称" />
    </div>
  </a-modal>
</template>
<script lang="ts">
  import { ref, reactive, watch, toRaw, defineComponent } from 'vue';
  import { useModalInner, BasicModal, useModal } from '/@/components/Modal';
  import { randomString } from '/@/utils/common/compUtils';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { Modal, Divider, Empty } from 'ant-design-vue';
  import { createLocalStorage } from '/@/utils/cache';
  import { useRoute } from 'vue-router';
  import { FormSchemaFactory } from '../../../use/FormSchemaFactory';
  import OnlineSuperQueryValComponent from './SuperQueryValComponent.vue';
  import { MinusCircleOutlined, PlusOutlined, FileTextOutlined, CloseCircleOutlined, AppstoreTwoTone } from '@ant-design/icons-vue';

  const FORM_VIEW_TO_QUERY_VIEW = {
    password: 'text',
    file: 'text',
    image: 'text',
    textarea: 'text',
    umeditor: 'text',
    markdown: 'text',
    checkbox: 'list_multi',
    radio: 'list',
  };
  const SAVE_CODE_PRE = 'JSuperQuerySaved_';
  function useSuperQuery() {
    const { createMessage: $message } = useMessage();
    const formRef = ref();
    const dynamicRowValues = reactive({
      values: [],
    });
    const matchType = ref('and');
    const [registerModal, { setModalProps }] = useModalInner(() => {
      setModalProps({ confirmLoading: false });
    });
    const view2QueryViewMap = Object.assign({}, { link_down: 'text' }, FORM_VIEW_TO_QUERY_VIEW);
    function handleSubmit() {
      console.log('handleSubmit', dynamicRowValues.values);
    }
    function handleCancel() {}
    function setFormModel(key, value, item) {
      console.log('setFormModel', key, value);
      item['val'] = value;
    }
    const fieldProperties = ref({});
    const fieldTreeData = ref([]);
    function init(json) {
      console.log('=============');
      console.log('=============', json);
      console.log('=============');
      let { allFields, treeData } = getAllFields(json);
      fieldProperties.value = allFields;
      fieldTreeData.value = treeData;
    }
    function addOne(index) {
      let item = {
        field: void 0,
        rule: 'eq',
        val: '',
        key: randomString(16),
      };
      if (index === false) {
        dynamicRowValues.values = [];
        dynamicRowValues.values.push(item);
      } else if (index === true) {
        if (dynamicRowValues.values.length == 0) {
          dynamicRowValues.values.push(item);
        }
      } else {
        dynamicRowValues.values.splice(++index, 0, item);
      }
    }
    function removeOne(item) {
      let arr = toRaw(dynamicRowValues.values);
      let index = -1;
      for (let i = 0; i < arr.length; i++) {
        if (item.key == arr[i].key) {
          index = i;
          break;
        }
      }
      if (index != -1) {
        dynamicRowValues.values.splice(index, 1);
      }
    }
    const defaultInput = {
      field: 'val',
      label: '测试',
      component: 'Input',
    };
    function getSchema(item, index) {
      let map = fieldProperties.value;
      let prop = map[item.field];
      if (!prop) {
        return defaultInput;
      }
      if (view2QueryViewMap[prop.view]) {
        prop.view = view2QueryViewMap[prop.view];
      }
      let temp = FormSchemaFactory.createFormSchema(item.field, prop);
      temp.noChange();
      temp.asSearchForm();
      temp.updateField(item.field + index);
      const setFieldValue = (values) => {
        item['val'] = values[item.field];
      };
      temp.setFunctionForFieldValue(setFieldValue);
      let schema = temp.getFormItemSchema();
      if (['empty', 'not_empty'].includes(item.rule)) {
        schema.componentProps = Object.assign({}, schema.componentProps, { disabled: true });
      }
      return schema;
    }
    const saveTreeData = ref('');
    const $ls = createLocalStorage();
    const saveInfo = reactive({
      visible: false,
      title: '',
      content: '',
      saveCode: '',
    });
    const loading = ref(false);
    const route = useRoute();
    watch(
      () => route.fullPath,
      (val) => {
        console.log('fullpath', val);
        initSaveQueryInfoCode();
      }
    );
    const currentPageSavedArray = ref([]);
    watch(
      () => currentPageSavedArray.value,
      (val) => {
        let temp = [];
        if (val && val.length > 0) {
          val.map((item) => {
            let key = randomString(16);
            temp.push({
              title: item.title,
              slots: { icon: 'custom' },
              value: key,
            });
          });
        }
        saveTreeData.value = temp;
      },
      { immediate: true, deep: true }
    );
    function initSaveQueryInfoCode() {
      let code = SAVE_CODE_PRE + route.fullPath;
      saveInfo.saveCode = code;
      let list = $ls.get(code);
      if (list && list instanceof Array) {
        currentPageSavedArray.value = list;
      }
    }
    initSaveQueryInfoCode();
    function handleSave() {
      let fieldArray = getQueryInfo();
      if (!fieldArray) {
        $message.warning('空条件不能保存');
        return;
      }
      let content = JSON.stringify(fieldArray);
      openSaveInfoModal(content);
    }
    function openSaveInfoModal(content) {
      saveInfo.visible = true;
      saveInfo.title = '';
      saveInfo.content = content;
    }
    function doSaveQueryInfo() {
      let { title, content, saveCode } = saveInfo;
      let index = getTitleIndex(title);
      if (index >= 0) {
        Modal.confirm({
          title: '提示',
          content: `${title} 已存在，是否覆盖？`,
          okText: '确认',
          cancelText: '取消',
          onOk: () => {
            currentPageSavedArray.value.splice(index, 1, {
              content,
              title,
              type: matchType.value,
            });
            $ls.set(saveCode, currentPageSavedArray.value);
            saveInfo.visible = false;
            $message.success('保存成功');
          },
        });
      } else {
        currentPageSavedArray.value.push({
          content,
          title,
          type: matchType.value,
        });
        $ls.set(saveCode, currentPageSavedArray.value);
        saveInfo.visible = false;
        $message.success('保存成功');
      }
    }
    function getTitleIndex(title) {
      let savedArray = currentPageSavedArray.value;
      let index = -1;
      for (let i = 0; i < savedArray.length; i++) {
        if (savedArray[i].title == title) {
          index = i;
          break;
        }
      }
      return index;
    }
    function getQueryInfo(isEmit = false) {
      var _a;
      let arr = dynamicRowValues.values;
      if (!arr || arr.length == 0) {
        return false;
      }
      let fieldArray = [];
      let fieldProps = fieldProperties.value;
      for (let item of arr) {
        let allowEmpty = ['empty', 'not_empty'].includes(item.rule);
        if (item.field && (allowEmpty || item.val || item.val === 0) && item.rule) {
          let prop = fieldProps[item.field];
          let formatValue = (_a = prop == null ? void 0 : prop.formatValue) != null ? _a : (v) => v;
          let tempVal = toRaw(item.val);
          if (tempVal instanceof Array) {
            tempVal = tempVal.map((v) => formatValue(v)).join(',');
          } else {
            tempVal = formatValue(tempVal);
          }
          let fieldName = getRealFieldName(item);
          let obj = {
            field: fieldName,
            rule: item.rule,
            val: tempVal,
          };
          if (isEmit === true) {
            let prop2 = fieldProps[item.field];
            if (prop2) {
              obj['type'] = prop2.view;
              obj['dbType'] = prop2.type;
            }
          }
          fieldArray.push(obj);
        }
      }
      if (fieldArray.length == 0) {
        return false;
      }
      return fieldArray;
    }
    function getRealFieldName(item) {
      let fieldName = item.field;
      if (fieldName.indexOf('@') > 0) {
        fieldName = fieldName.replace('@', ',');
      }
      return fieldName;
    }
    function handleTreeSelect(key, { node }) {
      console.log(key, node);
      let title = node.dataRef.title;
      let arr = currentPageSavedArray.value.filter((item) => item.title == title);
      if (arr && arr.length > 0) {
        let { content, type } = arr[0];
        let data = JSON.parse(content);
        let rowsValues = [];
        for (let item of data) {
          item.field = item.field.replace(',', '@');
          rowsValues.push(Object.assign({}, { key: randomString(16) }, item));
        }
        dynamicRowValues.values = rowsValues;
        matchType.value = type;
      }
    }
    function handleRemoveSaveInfo(title) {
      console.log(title);
      let index = getTitleIndex(title);
      if (index >= 0) {
        currentPageSavedArray.value.splice(index, 1);
        $ls.set(saveInfo.saveCode, currentPageSavedArray.value);
      }
    }
    function getAllFields(properties) {
      let allFields = {};
      let order = 1;
      let treeData = [];
      if (properties.properties) {
        properties = properties.properties;
      }
      Object.keys(properties).map((field) => {
        let item = properties[field];
        if (item.view == 'table') {
          let subProps = item['properties'] || item['fields'];
          let subTableOrder = order * 100;
          let subNode = {
            title: item.title,
            value: field,
            disabled: true,
            children: [],
            order: subTableOrder,
          };
          Object.keys(subProps).map((subField) => {
            let subItem = subProps[subField];
            subItem['order'] = subTableOrder + subItem['order'];
            let subFieldKey = field + '@' + subField;
            allFields[subFieldKey] = subItem;
            subNode.children.push({
              title: subItem.title,
              value: subFieldKey,
              isLeaf: true,
              order: subItem['order'],
            });
          });
          orderField(subNode);
          treeData.push(subNode);
          order++;
        } else {
          let fieldKey = field;
          allFields[fieldKey] = item;
          treeData.push({
            title: item.title,
            value: fieldKey,
            isLeaf: true,
            order: item.order,
          });
        }
      });
      orderField(treeData);
      return { allFields, treeData };
    }
    function orderField(data) {
      let arr = data.children || data;
      arr.sort(function (a, b) {
        return a.order - b.order;
      });
    }
    function initDefaultValues(values) {
      const { params, matchType: matchType2 } = values;
      if (params) {
        let rowsValues = [];
        for (let item of params) {
          rowsValues.push(Object.assign({}, { key: randomString(16) }, item));
        }
        dynamicRowValues.values = rowsValues;
        matchType2.value = matchType2;
      }
    }
    return {
      formRef,
      init,
      dynamicRowValues,
      matchType,
      registerModal,
      handleSubmit,
      handleCancel,
      handleSave,
      doSaveQueryInfo,
      saveInfo,
      saveTreeData,
      handleRemoveSaveInfo,
      handleTreeSelect,
      fieldTreeData,
      addOne,
      removeOne,
      setFormModel,
      getSchema,
      loading,
      getQueryInfo,
      initDefaultValues,
    };
  }

  export default defineComponent({
    name: 'OnlineSuperQuery',
    components: {
      BasicModal,
      MinusCircleOutlined,
      PlusOutlined,
      OnlineSuperQueryValComponent,
      FileTextOutlined,
      CloseCircleOutlined,
      AppstoreTwoTone,
      Divider,
    },
    props: {
      config: {
        type: Object,
        default: [],
      },
      status: {
        type: Boolean,
        default: false,
      },
      online: {
        type: Boolean,
        default: false,
      },
    },
    emits: ['search'],
    setup(props, { emit }) {
      const [registerFormModal, formModal] = useModal();
      const { createMessage: $message } = useMessage();
      const historyCollapsed = ref(true);
      function handleCancel() {
        formModal.closeModal();
      }
      function handleSubmit() {
        if (props.online === true) {
          let dataArray = getQueryInfo(true);
          if (dataArray && dataArray.length > 0) {
            emit('search', dataArray, matchType.value);
          } else {
            $message.warning('空条件无法查询！');
          }
        } else {
          let dataArray = getQueryInfo(true);
          if (dataArray && dataArray.length > 0) {
            let result = getSuperQueryParams(dataArray);
            emit('search', result);
          } else {
            $message.warning('空条件无法查询！');
          }
        }
      }
      function getSuperQueryParams(dataArray) {
        let arr = [];
        for (let item of dataArray) {
          let field = item.field;
          let val = item.val;
          if (val instanceof Array) {
            val = val.join(',');
          }
          arr.push(Object.assign({}, item, { field, val }));
        }
        if (arr.length > 0) {
          superQueryFlag.value = true;
        } else {
          superQueryFlag.value = false;
        }
        let result = {
          superQueryMatchType: matchType.value,
          superQueryParams: encodeURI(JSON.stringify(arr)),
        };
        return result;
      }
      function handleReset() {
        dynamicRowValues.values = [];
        addOne(false);
        let result = getSuperQueryParams([]);
        emit('search', result);
      }
      const {
        formRef,
        init,
        dynamicRowValues,
        matchType,
        registerModal,
        handleSave,
        doSaveQueryInfo,
        saveInfo,
        saveTreeData,
        handleTreeSelect,
        handleRemoveSaveInfo,
        fieldTreeData,
        addOne,
        removeOne,
        setFormModel,
        getSchema,
        loading,
        getQueryInfo,
        initDefaultValues,
      } = useSuperQuery();
      const superQueryFlag = ref(false);
      watch(
        () => props.status,
        (val) => {
          superQueryFlag.value = val;
        },
        { immediate: true }
      );
      function handleOpen() {
        formModal.openModal();
        addOne(true);
      }
      function getPopupContainer() {
        return document.getElementsByClassName('jee-super-query-form')[0];
      }
      function onFinish(a) {
        console.log('onfinish', a);
      }
      function handleChangeField(item) {
        item['val'] = '';
      }
      watch(
        () => props.config,
        (val) => {
          if (val) {
            init(val);
          }
        },
        { immediate: true }
      );
      return {
        formRef,
        registerFormModal,
        init,
        handleChangeField,
        dynamicRowValues,
        matchType,
        historyCollapsed,
        registerModal,
        handleSubmit,
        handleCancel,
        handleSave,
        handleReset,
        doSaveQueryInfo,
        saveInfo,
        saveTreeData,
        handleTreeSelect,
        handleRemoveSaveInfo,
        fieldTreeData,
        addOne,
        removeOne,
        setFormModel,
        getSchema,
        loading,
        onFinish,
        getPopupContainer,
        superQueryFlag,
        handleOpen,
        initDefaultValues,
        simpleImage: Empty.PRESENTED_IMAGE_SIMPLE,
      };
    },
  });
</script>

<style lang="less">
  .jee-super-query-form {
    max-height: 300px;
    overflow-y: auto;
  }
  .jee-super-query-form .ant-form-item {
    margin-bottom: 9px;
  }
  .j-super-query-history-tree .ant-tree-switcher {
    width: 0px;
  }
  .j-super-query-history-tree .ant-tree-node-content-wrapper {
    width: 100%;
  }
  .j-super-query-history-tree .ant-tree-node-content-wrapper:hover {
    background-color: #e6f7ff !important;
    border-radius: 0;
  }
  .j-super-query-history-tree .ant-tree-treenode-switcher-close .ant-tree-title {
    display: inline-block;
    width: calc(100% - 30px);
  }
  .j-super-query-history-tree .ant-tree-treenode-switcher-close .ant-tree-title > div {
    display: flex;
    justify-content: space-between;
  }
  .j-super-query-history-tree .ant-tree-treenode-switcher-close .ant-tree-title > div .icon-cancle {
    display: none;
    color: #666;
  }
  .j-super-query-history-tree .ant-tree-treenode-switcher-close .ant-tree-title > div .icon-cancle:hover {
    color: #000;
  }
  .j-super-query-history-tree .ant-tree-treenode-switcher-close:hover .icon-cancle {
    display: inline-block !important;
  }
  .j-super-query-history-tree .ant-card-body {
    padding: 0;
  }

  .j-super-query-history-card {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 2;
    width: 150px;
    min-height: 200px;
    box-shadow: 0 0 10px #0003;
  }

  .j-super-query-history-card.collapsed {
    right: -150px;
  }

  .j-super-query-history-card .collapse-box {
    position: absolute;
    top: calc(50% - 15px);
    left: -20px;
    width: 20px;
    height: 30px;
    background-color: #fff;
    border: 1px solid #e8e8e8;
    border-left: none;
    border-right-color: #fff;
    border-radius: 15px 0 0 15px;
    cursor: pointer;
    transition: all 0.3s;
    z-index: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    box-shadow: -4px 0 6px #0000001a;
  }

  .j-super-query-history-card .collapse-box:hover {
    background-color: #f5f5f5;
  }

  .j-super-query-history-card .collapse-box .app-iconify {
    font-size: 16px;
    position: relative;
    right: -3px;
    color: #666;
  }

  .j-super-query-history-card.collapsed .app-iconify {
    right: 0;
  }

  .j-super-query-history-card .ant-card-body,
  .j-super-query-history-card .ant-card-head {
    padding: 8px;
    min-height: 43px;
  }

  .j-super-query-history-card .ant-card-body .ant-card-head-title,
  .j-super-query-history-card .ant-card-head .ant-card-head-title {
    padding: 0;
  }

  @media only screen and (max-width: 1050px) {
    .jee-super-query-form .ant-space {
      flex-direction: column;
      gap: 0 !important;
      margin-bottom: 16px !important;
    }
    .jee-super-query-form .ant-space-item {
      width: 100%;
    }
    .jee-super-query-form .ant-form-item {
      width: 100% !important;
    }
  }
</style>
